package com.wontube.smr.bo.sites.moviefone;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.ibatis.session.SqlSession;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.wontube.client.extension.utils.DateUtils;
import com.wontube.client.extension.utils.NumberUtils;
import com.wontube.client.extension.utils.StringUtils;
import com.wontube.core.dao.mybatis.QueryExample;
import com.wontube.smr.bo.constants.SiteConstants;
import com.wontube.smr.bo.constants.StandarAreas;
import com.wontube.smr.client.model.po.Movie;
import com.wontube.smr.client.model.po.MovieGenre;
import com.wontube.smr.dao.bo.MovieDao;
import com.wontube.smr.dao.mapper.MovieGenreMapper;
import com.wontube.smr.dao.mapper.MovieMapper;
import com.wontube.smr.pub.DefaultDBHelper;

/**
 * moviefone crawl
 * 
 * @author hewc@wondershare.cn
 * 
 */
public final class MovieFoneObtainBO {
	private final static String THEATER_URL_FORMAT = "http://www.moviefone.com/new-movie-releases?page={}";
	private final static String COMINGSOON_URL_FORMAT = "http://www.moviefone.com/coming-soon?page={}";
	private final static String YAHOO_MOVIE_CHART_URL = "http://movies.yahoo.com/box-office/";

	//private static final String NO_IMG = "http://o.aolcdn.com/dims-global/dims/GLOB/5/125/185/75/http://o.aolcdn.com/artqa/os/repos/movies/movie_posters/0000_p_m";

	private static final Logger logger = LoggerFactory.getLogger(MovieFoneObtainBO.class);

	private final static int CONNECT_READ_TIMEOUT = 30 * 1000;
	private final static String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1";
	private final static String REFERRER = "http://www.moviefone.com/";
	
	private final static Pattern VIDEO_ID_PATTERN = Pattern.compile("^.+/(\\d+)/main$");	
	
	private MovieFoneObtainBO(){}
	
	/**
	 * movies in theater
	 * save or update to movie table with movie_type = 'Trailer'
	 * @return
	 */
	public static int saveTheaterMovies(){
		return grabAndSaveTraillers(THEATER_URL_FORMAT);
	}
	
	/**
	 * coming soon movies
	 * @return
	 */
	public static int saveComingsoonMovies(){
		return grabAndSaveTraillers(COMINGSOON_URL_FORMAT);
	}
	
	/**
	 * 从yahoo得到排行榜的电影名到对应到抓取到的movie
	 */	
	public static int obtainMovieChart() {		
		int count = 0;
		Document doc = getWebDocument(YAHOO_MOVIE_CHART_URL);
		if(doc != null){
			List<String> names = new ArrayList<String>();
			Elements titleEles = doc.select("div.yom-mod > div.bd > table.top-list > tbody > tr.element > td.title > div > a");			
			for (Element ele : titleEles) {
				names.add(ele.text().trim());				
			}			
			count = MovieDao.savePopWeekMovie(names);
		}		
		
		return count;
	}
	
	private static int grabAndSaveTraillers(final String urlFormat){
		int count = 0;
		int pageCount = 1;
		for (int page = 1; page <= pageCount; page++) {
			String gurl = StringUtils.format(urlFormat, page);
			Document doc = getMFDocument(gurl);
			if(doc != null){
				//reset page count
				if(page == 1){
					pageCount = NumberUtils.parseInt(doc.select("#penultimatePage").text());
				}
				List<Movie> movies = obtainMovies(doc);
				
				SqlSession session = DefaultDBHelper.getBatchSqlSession();
				Date version = DateUtils.getNow();				
				try {
					MovieMapper mapper = session.getMapper(MovieMapper.class);
					MovieGenreMapper genreMapper = session.getMapper(MovieGenreMapper.class);
					for (Movie movie : movies) {
						movie.setVersion(version);						
						String movieId = movie.getId();
						Movie temp = mapper.selectByPrimaryKey(movieId);
						boolean inserted = false;
						if(temp != null){
							//update
							movie.setSortIndex(++count);
							mapper.updateByPrimaryKey(movie);
						}else{
							
							//可能跟imdb同名
							QueryExample ex = new QueryExample();
							ex.or().addCriterion("title=", movie.getTitle())
									.addCriterion("movie_type=", Movie.TYPE_TRAILER);
							
							if(mapper.countByExample(ex) == 0){
								//insert
								movie.setSortIndex(++count);
								mapper.insert(movie);
								inserted = true;
							}
						}
						
						if(inserted){
							//考虑genre问题
							String genreNames = movie.getGenre();
							if( ! StringUtils.isNullOrEmpty(genreNames)){		
								String[] genres = genreNames.split(",");
								for (String genre : genres) {
									QueryExample ex = new QueryExample();
									ex.or().addCriterion("movie_genre.movie_id=", movieId)
											.addCriterion("movie_genre.genre_name=", genre);
									
									if(genreMapper.countByExample(ex) == 0){
										//增加关联
										MovieGenre movieGenre = new MovieGenre();
										movieGenre.setId(UUID.randomUUID().toString());
										movieGenre.setMovieId(movieId);
										movieGenre.setGenreName(genre);
										genreMapper.insert(movieGenre);
									}
								}		
							}		
						}
					}
					
					session.commit();
				} finally {
					session.close();
				}				
			}
		}
		return count;
	}
	
	private static List<Movie> obtainMovies(Document doc) {
		List<Movie> movies = new ArrayList<Movie>();
		Elements movieElms = doc.select("#k > div.hub-body > div.hub-item > div.movie");
		for (Element ele : movieElms) {
			String url = ele.select("a.movieTitle").attr("href");			
			String videoId = getVideoIdFromPattern(url);
			if(videoId == null){
				continue;
			}
			
			Movie movie = null;
			try {
				movie = obtainMovieDetail(url);
			} catch (Exception e) {
				logger.error("error happen when parse {}", url, e);
			}			
			
			if(movie == null){
				continue;
			}			
			
			//已设置videoId字段
			movie.setId(SiteConstants.ID_PREFIX_MOVIEFONE + videoId);
			movie.setItemUrl(url);
			
			String img = ele.select("img.thePoster").attr("src");
			movie.setThumbnail(img);			
			String title = ele.select("a.movieTitle").text().trim();	
			movie.setTitle(title);
			movie.setTitleInitial(StringUtils.getInitial(title));
			movie.setArea(StandarAreas.DEFAULT);
			//能嵌入flash播放
			movie.setAllowEmbed(1);
			movie.setMovieType(Movie.TYPE_TRAILER);
			movie.setWebsite(SiteConstants.WEBSITE_MOVIEFONE);			
			
			//修正genres
			movie.setGenre(MovieFontMovieGenres.remendAllGenres(movie.getGenre()));
			
			movies.add(movie);
		}
		return movies;
	}

	private static Movie obtainMovieDetail(String url) {
		Document doc = getMFDocument(url);
		if(doc != null){
			//no desc no keep
			Element descEle = doc.select("#movie-main-synopsis > p").first();
			if(descEle != null){
				//切取播放id
				String videoId = cutPlayVideoId(doc);			
				if(StringUtils.isNullOrEmpty(videoId)){
					return null;
				}
				
				Movie movie = new Movie();
				movie.setVideoId(videoId);
				movie.setDescription(descEle.ownText().trim());
				
				Elements rows = doc.select("#movie-details > div.body > div.row");
				for (Element ele : rows) {
					String label = ele.select("div.label").text().trim();		
					String info = ele.select("div.info").text().trim();
					if("Theatrical Release Date:".equals(label)){						
						SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
						movie.setPublishTime(DateUtils.parse(format, info));
					}else if("Starring:".equals(label)){						
						movie.setActors(info);
					}else if("Director(s):".equals(label)){
						movie.setDirector(info);
					}else if("Genre(s):".equals(label)){
						movie.setGenre(info);
					}
				}
				
				//score
				int score = NumberUtils.parseInt(doc.select("#critic-rating > span.critic-review").text().trim());
				movie.setScore(BigDecimal.valueOf((score/10.0d)));
								
				return movie;
			}
		}
		
		return null;
	}

	private static String cutPlayVideoId(Document doc) {
		String videoId = null;
		String playdiv = doc.select("#AOLVP_us_234523452345").html();
		if( ! playdiv.isEmpty()){
			int s = playdiv.indexOf("{");
			int e = playdiv.indexOf("}");
			String jo = playdiv.substring(s, e + 1);
			try {
				BufferedReader reader = new BufferedReader(new StringReader(jo));		
				String line = null;
				while( (line = reader.readLine()) != null){
					String vv = line.trim();
					if(vv.startsWith("\"videoid\"")){
						vv = vv.substring(9);
						int s1 = vv.indexOf("\"");
						int s2 = vv.lastIndexOf("\"");
						videoId = vv.substring(s1 + 1, s2);
						break;
					}
				}
			} catch (Exception e2) {				
			}									
		}
		return videoId;
	}

	private static String getVideoIdFromPattern(String url) {
		String videoId = null;
		Matcher m = VIDEO_ID_PATTERN.matcher(url);
		if(m.matches()){
			videoId = m.group(1);
		}
		
		if(StringUtils.isNullOrEmpty(videoId)){
			videoId = null;
			//log
			logger.warn("cannot get video id from {}", url);
		}
		return videoId;
	}
	
	private static Document getWebDocument(String url) {
		try {
			return Jsoup.connect(url).timeout(CONNECT_READ_TIMEOUT).userAgent(USER_AGENT).get();
		} catch (IOException e) {
			logger.error(e.toString());
		}
		return null;
	}
	
	private static Document getMFDocument(String url){
		try {
			return Jsoup.connect(url).timeout(CONNECT_READ_TIMEOUT).userAgent(USER_AGENT).referrer(REFERRER).get();
		} catch (IOException e) {
			logger.error(e.toString());
		}
		return null;
	}
}
